import React, {FC, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from "react";
import {useTranslation} from "react-i18next";
import {Input, Spin} from "antd";
import "ag-grid-enterprise";
import {AgGridReact} from "ag-grid-react";
import 'ag-grid-community/styles/ag-grid.min.css';
import 'ag-grid-community/styles/ag-theme-alpine.min.css';
import "./css/CTable.less";
import update from "react-addons-update";
import {AxiosGet, AxiosPost, AxiosSer} from "@core/services/HttpService";
import {configChange} from "@core/Config";
import {
    formatLangStr,
    getObjAttrFun,
    isArray,
    isBoolean,
    isFunction,
    isNumber,
    isString,
    treeFilterMap,
    treeFind,
    treeMap,
} from "@core/utils";
import {getTableView, getTableViewList} from "@core/services/ViewService";
import {getTableComAll} from "./CTableComponents";
import useStateRef from "@core/customUse/useStateRef";
import useDebounce from "@core/customUse/useDebounce";
import CtableCustomSearch from "./CTableCustomSearch.tsx";
import {generateRandomId, getObjByRule} from "../../utils";


let pageSize: number, axiosSerMenuKey: string, tableFakeServer: any,
    editStatusKey: string = "editStatus",
    treeTablePathKey: string = "treeTablePath",
    treeGroupKey: string = "treeGroup";

configChange((config: any) => {
    pageSize = config.pageSize;
    axiosSerMenuKey = config.axiosSerMenuKey;
});

interface CTableProps {
    init: any,//获取表格对象api
    key: string,//表格key
    menuId: string,//模块菜单id
    view: string | any[],//表格列头视图
    ds: any,//表格列头视图
    isTreeTable: boolean | string,//是否树形表格
    tableApi: any,//表格基本属性
    rowKey: string,//表格唯一键
    parentKey: string,//父唯一键
    hasCheckbox?: boolean | undefined,//是否有选择框
    isSideBar?: boolean,//是否有列筛选功能
    height?: number | string,//表格高度
    headerHeight?: number | undefined,//表格头部高度
    rowHeight?: number | undefined,//数据行高
    dataSource?: object[] | undefined,//表格直接数据
    selectIds?: string[] | undefined,//表格默认选中数据数据
    rowSelection: 'single' | 'multiple' | 'clickMultiple',//单选 single | multiple 多选 默认
    autoExpand?: number | boolean | undefined; //自动展开层级
    searchAutoExpand?: boolean,
    isCopyObject?: boolean | undefined //是否显示右键复制对象功能
    isReloadObject?: any //是否显示右键刷新对象功能
    rowUrl?: string, //查询基本信息url
    isParentLinkChild?: boolean | undefined //选中父的时候是否联动选中子
    isPagination?: boolean,//是否开启分页
    isShowHeader?: boolean | string,//是否显示搜索
    isInitSearch?: boolean,//是否初始化搜索
    isLazyData: boolean,//是否懒加载数据，必须isPagination为false时才生效
    otherRenderFn?: any | undefined,//拓展表格自定义渲染方法
    dataSourceFilter?: Function,//数据过滤方法
    getRowStyle?: Function //控制行样式功能,
    isRowSelectable?: Function //控制行不可选中功能,
    isAddVirtual?: boolean //是否自动添加虚拟Id
    onSelectChange?: Function //数据选中方法,
    onCellDoubleClicked?: Function //数据选中方法,
    getLinkParams?: Function //数据选中方法,
    otherTableParams?: any,
    columnsFilter?: any,
    searchFn: any,
    copyType: any,
    otherSearchFn: any,
    isExpandObject: any,
    isShowKeyWordSearch: boolean //关键词搜索字段
}

const CTable: FC<CTableProps> = (props) => {
    const {t} = useTranslation();

    let gridTable = useRef();
    let gridColumn = useRef();
    let searchParamsRef = useRef({});
    let allDataRef = useRef([]);
    let initTableParamsRef = useRef({});
    let expandIdsObjRef: any = useRef({});
    let customSearchRef: any = useRef();

    const [loading, setLoading] = useState<boolean>(false),
        [firstColumn, setFirsColumn] = useState<any>(),
        [column, setColumn] = useState<any[]>([]),
        [initTableParams, setInitTableParams] = useStateRef({}, initTableParamsRef),
        [isSearchTable, setIsSearchTable] = useState<boolean>(false),
        [total, setTotal] = useState<number>(),
        [columnsAll, setColumnsAll] = useState<any>({}),
        [selectCount, setSelectCount] = useState<number>(0);

    // 获取当前表格唯一建属性
    const getKey: Function = useCallback(() => {
        return props.rowKey || "id";
    }, [props.rowKey]);

    // 设置表格数据唯一key
    const getRowId: Function = useCallback((params: any) => {
        return params.data[getKey()];
    }, [props.rowKey]);

    // 是否树型表格
    const isTreeTable: Function = useCallback(() => {
        return !!props.isTreeTable;
    }, [props.isTreeTable]);

    //是否懒加载数据
    const isLazyTable: Function = useCallback(() => {
        return !!props.isTreeTable || props.isLazyData;
    }, [props.isLazyData, props.isTreeTable]);

    // 获取树形表格路径
    const getDataPath: Function = useCallback((row: any) => {
        return row[treeTablePathKey];
    }, [firstColumn]);

    // 判断是都为可以展开的父节点
    const isServerSideGroup: Function = useCallback((row: any) => {
        return row[treeGroupKey];
    }, []);

    // 自动展开层级
    const isServerSideGroupOpenByDefault: Function = useCallback((row: any) => {
        const {searchAutoExpand = true, autoExpand = false}: {
            searchAutoExpand: boolean,
            autoExpand: number | boolean | undefined,
        } = props;
        if (row.data.autoExpand) {
            return true
        } else if (isSearchTable) {
            const {treeKey = "children"} = props.tableApi || {};
            if (row.data[treeKey] && row.data[treeKey].length) {
                return searchAutoExpand;
            }
        } else if (isNumber(autoExpand)) {
            return (row.rowNode.level + 1) < autoExpand;
        } else {
            return !!autoExpand;
        }
    }, [props.autoExpand, props.searchAutoExpand, isSearchTable]);

    // 树形表格展开时指定当前对象唯一件属性
    const getServerSideGroupKey: Function = useCallback((row: any) => {
        return row && row[getKey()];
    }, [props.rowKey]);

    //设置属性表格第一列
    const autoGroupColumnDef = useMemo(() => {
        if (!firstColumn) {
            return firstColumn;
        }
        return {
            ...firstColumn,
            cellRenderer: "agGroupCellRenderer",
            cellRendererParams: {
                ...firstColumn.cellRendererParams,
                innerRenderer: firstColumn.cellRenderer,
            }
        };
    }, [firstColumn]);

    //设置属性表格第一列
    const tableSideBar = useMemo(() => {
        let {isShowHeader = true, isShowKeyWordSearch} = props;
        let toolPanels: any = [
            {
                id: 'columns',
                labelDefault: t("screen"),
                labelKey: 'columns',
                iconKey: 'columns',
                toolPanel: 'agColumnsToolPanel',
                toolPanelParams: {
                    suppressRowGroups: true,
                    suppressValues: true,
                    suppressPivots: true,
                    suppressPivotMode: true,
                    suppressSideButtons: true,
                    suppressColumnExpandAll: true,
                },
            }
        ]
        if (isShowHeader && isShowKeyWordSearch) {
            toolPanels.push({
                id: "customStats",
                labelDefault: t('keywordSearch'),
                labelKey: "filters",
                iconKey: "columns",
                toolPanel: CtableCustomSearch,
                toolPanelParams: {
                    init: customSearchRef
                }
            })
        }
        return {toolPanels}
    }, [firstColumn]);

    //获取表格选中数据方法
    const getTableSelectedRows: Function = useCallback(() => {
        let rows: any[] = [];
        if (isLazyTable()) {
            gridTable.current?.forEachNode((node: any) => {
                if (node.selected !== false) {
                    rows.push(node.data)
                }
            })
            //暂时注释，开启联级选择后，全选反选有问题，因此暂时取消选择
            // let state: any = gridTable.current.getServerSideSelectionState();
            // let selectAll: boolean = props.isParentLinkChild ? state.selectAllChildren : state.selectAll;
            // let selectKeys: string[] = [];
            // if (props.isParentLinkChild) {
            //     treeEach(state.toggledNodes || [], (node: any) => {
            //         selectKeys.push(node.nodeId);
            //     }, "toggledNodes")
            // } else {
            //     selectKeys = state.toggledNodes || [];
            // }
            // if (selectAll) {
            //     gridTable.current.forEachNode((node: any) => {
            //         if (selectKeys.indexOf(node.data ? node.data[rowKey] : node.key) === -1) {
            //             rows.push(node.data)
            //         }
            //     })
            // } else {
            //     gridTable.current.forEachNode((node: any) => {
            //         if (selectKeys.indexOf(node.data ? node.data[rowKey] : node.key) !== -1) {
            //             rows.push(node.data)
            //         }
            //     })
            // }
        } else {
            rows = gridTable.current.getSelectedRows();
        }
        return rows;
    }, [props.isLazyData, props.rowKey, props.isParentLinkChild]);

    const getTableAllRows: Function = useCallback(() => {
        let allData: any[] = treeMap(allDataRef.current, (children: any[], item: any) => {
            let node: any = gridTable.current.getRowNode(item[getKey()]) || {};
            return {
                ...item,
                ...(node.data || {}),
                children: children && children.length ? children : null
            }
        });
        return allData;
    }, []);

    // 表格列头排序方法
    const onSortChanged: Function = useCallback(({columnApi}: { columnApi: any }) => {
        let sortOption: any = columnApi.columnModel.sortController.getSortModel()[0] || {};
        loadTable(gridTable.current, {...initTableParams, sidx: sortOption.colId, sord: sortOption.sort});
    }, [initTableParams]);

    // 表格选择数据方法
    const onSelectionChanged: Function = useCallback(() => {
        let rows = getTableSelectedRows();
        setSelectCount(rows.length);
        props.onSelectChange && props.onSelectChange(rows);
    }, [props.onSelectChange]);

    // 表格行双击数据方法
    const onCellDoubleClicked: Function = useCallback((node: any) => {
        props.onCellDoubleClicked && props.onCellDoubleClicked(node.data);
    }, [props.onCellDoubleClicked]);

    // 设置行是否可以选中事件
    const isRowSelectable: Function = useCallback((params: any) => {
        if (props.isRowSelectable) {
            return props.isRowSelectable(params);
        }
        return true;
    }, [props.isRowSelectable]);

    // 设置行是否默认选中
    const isDefaultSelected: Function = useCallback((params: any) => {
        if (props.selectIds && props.selectIds.length) {
            let nodesToSelect: any[] = [];
            props.selectIds.forEach(i => {
                let node: any = params.api.getRowNode(i);
                if (node) {
                    nodesToSelect.push(node);
                }
            });
            params.api.setNodesSelected({nodes: nodesToSelect, newValue: true})
        }
    }, [props.selectIds, props.rowKey]);

    // 设置行样式事件
    const getRowStyle: Function = useCallback((params: any) => {
        if (props.getRowStyle) {
            return props.getRowStyle(params);
        }
        if (!params.data) {
            return {};
        }
        let style: any = {};
        switch (params.data[editStatusKey]) {
            case "add":
                style = {
                    ...style,
                    backgroundColor: "#E2EFDA"
                }
                break;
            case "update":
                style = {
                    ...style,
                    backgroundColor: "#FFC000"
                }
                break;
            case "delete":
                style = {
                    ...style,
                    backgroundColor: "#FF0000"
                }
                break;
            default:
                break;
        }
        return style;
    }, [props.getRowStyle]);

    //刷新行
    const reloadChildren = useCallback(async (e: any) => {
        let {rowUrl = '/dataManagement/object', isReloadObject} = props
        //获取到id，有时候没法用rowKey的时候，根据类型判断用哪个id
        let rowId = isBoolean(isReloadObject) ? getKey() : isReloadObject
        let res = await AxiosGet(rowUrl, {id: e.node.data[rowId]})
        if (res.data) {
            if (isTreeTable()) {
                let route = getParentPathById(gridTable.current, e.node.data[getKey()]).route;
                gridTable.current?.refreshServerSide({route: route, purge: true});
            }
            updateTableData({...res.data, [getKey()]: e.node.data[getKey()], [editStatusKey]: ''})
        } else {
            //被删除了
            deleteTableData([e.node.data[getKey()]])
        }
    }, [])

    const expandAllChildren = useCallback((row: any = null) => {
        let rowID = row ? row[getKey()] : allDataRef.current[0][getKey()];
        let node = gridTable.current.getRowNode(rowID)
        if (node) {
            node.setExpanded(true);
            setTimeout(() => {
                if (node.data.children) {
                    node.data.children.forEach((child: any) => {
                        if (child.children) {
                            expandAllChildren(child);
                        }
                    })
                }
            }, 50);
        }
    }, [])

    const copyToClipboard = useCallback((text: any) => {
        if (navigator.clipboard) {
            navigator.clipboard.writeText(text);
        } else {
            const input = document.createElement("textarea");
            input.value = text;
            document.body.appendChild(input);
            input.select();
            document.execCommand("copy"); // 已废弃但可临时使用
            document.body.removeChild(input);
        }
    }, [])

    //列移动
    const colMoveSet = useDebounce(async (event: any) => {
        let obj: any = {}
        let widthObj: any = {}
        event.columnApi.columnModel.gridColumns.forEach((item: any, index: any) => {
            // console.log('xx', item.colId, item.actualWidth, item.colDef.width)
            obj[item.colId] = index
            widthObj[item.colId] = item.actualWidth
        })
        let params: any = {
            ...columnsAll,
            alternativeColumns: []
        }
        if (columnsAll.alternativeColumns.length) {
            columnsAll.alternativeColumns.forEach((item: any) => {
                if (obj[formatLangStr(item.field)]) {
                    item.width = widthObj[formatLangStr(item.field)]
                    params.alternativeColumns[obj[formatLangStr(item.field)]] = item
                } else {
                    params.alternativeColumns[0] = item
                }
            })
        } else {
            columnsAll.containColumns.forEach((item: any) => {
                if (obj[formatLangStr(item.field)]) {
                    params.alternativeColumns[obj[formatLangStr(item.field)]] = item
                } else {
                    params.alternativeColumns[0] = item
                }
            })
        }
        let newData: any = []
        params.alternativeColumns.forEach((item: any) => {
            if (item) {
                newData.push(item)
            }
        })
        params.alternativeColumns = newData
        await AxiosPost('/sf-drs/platform/view/saveUserTableView', params)
        gridTable.current.closeToolPanel();
        columnsAll.alternativeColumns = params.alternativeColumns
        setColumnsAll({...columnsAll})
    }, 300, [])

    //列显示隐藏
    const colShowHideSet = useDebounce(async (event: any) => {
        let arr = event.columnApi.columnModel.gridColumns.map((item: any) => item.visible)
        let params = {
            ...columnsAll,
            alternativeColumns: []
        }
        delete params.columns
        params.alternativeColumns = columnsAll.containColumns.map((item: any, index: any) => {
            let newItem = JSON.parse(JSON.stringify(item))
            newItem.visible = arr[index + 1] ? 1 : 0
            columnsAll.columns[index].visible = arr[index] ? true : false
            return newItem
        })
        await AxiosPost('/sf-drs/platform/view/saveUserTableView', params)
        columnsAll.alternativeColumns = params.alternativeColumns
        setColumnsAll({...columnsAll})
    }, 300, [])

    // 初始化表格时加载，获取当前表格对象
    const onGridReady: Function = useCallback((e: any) => {
        gridTable.current = e.api;
        gridColumn.current = e.columnApi.columnModel;
        // 初始化表格，加载列头和数据
        initCTable(e.api);
        // e.api.addGlobalListener((type, event) => {
        //     console.log(type,"xxxxxxxxxxxx----type")
        // });
        e.api.addGlobalListener((type: any, event: any) => {
            // if (type === 'dragStopped') {
            //     colMoveSet(event)
            // }
            // if (type == 'columnVisible') {
            //     colShowHideSet(event)
            // }
        });
    }, [firstColumn, props.dataSource, props.isLazyData, props.isTreeTable, props.tableApi, props.isInitSearch]);

    //添加数据时当前选中项没有子数据
    const updateUnChildData: Function = useCallback((gridTableApi: any, id: string, data: any[]) => {
        let node = gridTableApi.getRowNode(id);
        if (!node) {
            return false;
        }
        const {treeKey = "children"}: {
            treeKey: string
        } = props.tableApi || {};
        node.key = id;
        // let item: any = gridTableApi.getRenderedNodes().find((k: any) => (k.data[getKey()] === id));
        // if (!item) {
        //     return true
        // }
        node.data[treeGroupKey] = true;
        node.data[treeKey] = node.data[treeKey] ? [...node.data[treeKey], ...data] : data;
        // item[treeKey] = node.data[treeKey];
        node.updateData(node.data);
        node.updateHasChildren();
        return true
    }, [props.tableApi, props.rowKey]);

    // 添加列表数据更新初始数据
    const updateInitData: Function = useCallback((data: any[]) => {
        data.forEach(item => {
            item[editStatusKey] = "add";
        });
        if (tableFakeServer && tableFakeServer.initData) {
            tableFakeServer.initData = [...tableFakeServer.initData, ...data];
        }
        return true
    }, []);

    //根据id获取树形表格位于路径
    const getParentPathById: Function = useCallback((gridTableApi: any, id: string, isAddLast: boolean = false) => {
        let node = gridTableApi.getRowNode(id);
        if (!node) {
            return {route: [], index: 0};
        }
        let idPath: string[] = [], {treeKey = "children"}: {
            treeKey: string
        } = props.tableApi || {};
        const getParentPath = (item: any) => {
            if (item.parent) {
                getParentPath(item.parent);
            }
            item.data && item.data[getKey()] && idPath.push(item.data[getKey()]);
        };
        getParentPath(node);
        return {
            route: idPath,
            index: isAddLast && node.data[treeKey] ? node.data[treeKey].length : 0
        };
    }, [props.tableApi, props.rowKey]);

    // 设置表格数据
    const setTableData: Function = useCallback((gridTableApi: any = gridTable.current) => {
        return isLazyTable() || isTreeTable() ? gridTableApi.setServerSideDatasource.bind(gridTableApi) : gridTableApi.setRowData.bind(gridTableApi);
    }, [props.isLazyData, props.isTreeTable]);

    // 修改表格数据
    const applyTableData: Function = useCallback((gridTableApi: any = gridTable.current) => {
        return isLazyTable() || isTreeTable() ? gridTableApi.applyServerSideTransaction.bind(gridTableApi) : gridTableApi.applyTransaction.bind(gridTableApi);
    }, [props.isLazyData, props.isTreeTable]);

    // 获取表格列头数据
    const loadView: Function = useCallback(async () => {
        const {view, hasCheckbox = false, ds = {}, getLinkParams}: {
            view: any,
            hasCheckbox: boolean | undefined,
            ds: any,
            getLinkParams: Function
        } = props;
        let res: any = {};
        if (isArray(view)) {
            if (view[0]?.headerName) {
                res.columns = view;
            } else {
                res.columns = await getTableViewList({containColumns: view}, {...ds, getLinkParams})
            }
        } else {
            res = await getTableView(view, {...ds, getLinkParams})
        }
        // res = isArray(view) ? {
        //     columns: view[0]?.headerName ? view : await getTableViewList({containColumns: view}, {...ds, getLinkParams})
        // } : (await getTableView(view, {...ds, getLinkParams}));
        if (isTreeTable() && !firstColumn) {
            setFirsColumn(res.columns[0]);
            res.columns = update(res.columns, {$splice: [[0, 1]]});
        } else if (firstColumn) {
            let index: number = res.columns.findIndex((i) => (i.field === firstColumn.field));
            if (index !== -1) {
                res.columns = update(res.columns, {$splice: [[index, 1]]});
            }
        }
        if (hasCheckbox && res.columns.findIndex(i => (i.key === "checkbox")) === -1) {
            res.columns = update(res.columns, {
                $unshift: [{
                    key: "checkbox",
                    width: 30,
                    minWidth: 30,
                    pinned: "left",
                    headerCheckboxSelection: true,
                    checkboxSelection: true,
                    showDisabledCheckboxes: true,
                }]
            })
        }
        if (props.columnsFilter) {
            res.columns = props.columnsFilter(res.columns)
        }
        setColumnsAll({...res})
        setColumn(res.columns);
    }, [props.view, props.hasCheckbox, props.ds, props.getLinkParams, firstColumn]);

    // 格式化树形数据
    const formatTreeTableData: Function = useCallback((data: any, isCreate: boolean) => {
        const {treeKey = "children", hasChildrenKey = "hasChildren"}: {
            treeKey: string,
            hasChildrenKey: string
        } = props.tableApi || {};
        let newData: any[] = treeMap(data, (children: any[], item: any) => {
            let isTree: boolean = false;
            if (item[treeKey] && item[treeKey].length > 0) {
                isTree = true;
            } else if (isString(hasChildrenKey)) {
                isTree = !!getObjAttrFun(item, hasChildrenKey);
            }
            return {
                ...item,
                [treeGroupKey]: isTree,
                [editStatusKey]: isCreate ? "add" : undefined,
                children
            }
        });
        return newData;
    }, [firstColumn, props.tableApi, props.isTreeTable]);

    // 创建一个获取数据方法
    const createFakeServer = useCallback((initData: any[]) => {
        tableFakeServer = {
            initData,
            getData: async function (grid: any): any {
                const {request}: {
                    request: any
                } = grid, {startRow}: {
                    startRow: number
                } = request;
                let page: number = Math.floor(startRow / pageSize) + 1, rows: any[];
                if (page > 1) {
                    rows = await loadListData(props.tableApi, {...searchParamsRef.current, page, rows: pageSize});
                } else {
                    rows = this.fakeServer.initData;
                }
                return rows;
            },
            getTreeData: async function (grid: any): any {
                const {request, parentNode} = grid, {treeKey = "children", hasChildrenKey = "hasChildren"}: {
                        treeKey: string | undefined, hasChildrenKey: string
                    } = props.tableApi || {},
                    {startRow, endRow}: {
                        startRow: number,
                        endRow: number
                    } = request;
                let list: any[] = parentNode.data ? parentNode.data.allChild || parentNode.data[treeKey] : this.fakeServer.initData;
                if (!list || (list.length == 0 && parentNode.data && !!getObjAttrFun(parentNode.data, hasChildrenKey))) {
                    list = isLazyTable() ? await loadTreeChildData(props.tableApi, parentNode.data || {}) : [];
                    // 存储后端一次性返回的数据
                    parentNode.data.allChild = list;
                }
                list = list.length >= pageSize ? list.slice(startRow, endRow) : list;
                let rows: any[] = list.map((item: any) => {
                    let isTree: boolean = false;
                    if (item[treeKey] && item[treeKey].length > 0) {
                        isTree = true;
                    } else if (isString(hasChildrenKey)) {
                        isTree = !!getObjAttrFun(item, hasChildrenKey);
                    }
                    return {
                        ...item,
                        [treeGroupKey]: isTree
                    }
                });
                return rows;
            },
        };
        return tableFakeServer;
    }, [props.tableApi, props.menuId, props.isLazyData, props.isTreeTable, props.rowKey, props.dataSourceFilter, initTableParams]);

    const createServerSideDatasource = useCallback((fakeServer: any) => {
        let {tableApi = {}} = props
        return {
            fakeServer,
            tableApi: tableApi,
            getRows: async function (grid: any) {
                let getData: any = isTreeTable() ? this.fakeServer.getTreeData.bind(this) : this.fakeServer.getData.bind(this)
                let rowData: object[] = await getData(grid);
                if (isTreeTable()) {
                    const {parentNode}: { parentNode: any } = grid, {treeKey = "children"}: {
                        treeKey: string
                    } = tableApi;
                    if (parentNode.id && props.isLazyData) {
                        let node: any = treeFind(allDataRef.current, (i: any) => i[getKey()] === parentNode.id);
                        if (node) {
                            node[treeKey] = [...(node[treeKey] || []), ...rowData];
                        }
                    } else if (!parentNode.id) {
                        allDataRef.current = [...allDataRef.current, ...rowData];
                    }
                } else {
                    allDataRef.current = [...allDataRef.current, ...rowData];
                }
                grid.success({
                    rowData
                })
            }
        }
    }, [props.tableApi, props.menuId, props.isLazyData, props.rowKey, props.isTreeTable, initTableParams]);

    const loadData: Function = useCallback(async (gridTableApi: any, searchParams: any = {}, searchUrl: string) => {
        setLoading(true);
        const {menuId, dataSource, tableApi = {}, dataSourceFilter, isAddVirtual = false}: {
            menuId: string,
            dataSource: any[],
            tableApi: any,
            dataSourceFilter: Function,
            isAddVirtual?: boolean
        } = props;
        if (dataSource) {
            allDataRef.current = dataSource;
            setTableData(gridTableApi)(dataSource);
            setLoading(false);
            return false;
        }
        let {url, params = {}, method = "get", initParams = {}}: {
            url: string,
            method?: string,
            params: any,
            initParams: any
        } = tableApi;
        params = {rows: pageSize, ...initParams, ...params};
        setInitTableParams(params);
        let {data = [], records}: {
            data: any,
            records: number
        } = searchUrl || url ? (await AxiosSer(searchUrl || url, method, {
            ...params, ...searchParams,
            [axiosSerMenuKey]: menuId
        })) : {};
        setTotal(records);
        if (isAddVirtual) {
            data = treeMap(data, (children, item) => {
                return {
                    ...item,
                    tableVirtualId: generateRandomId(),
                    children
                }
            })
        }
        if (isFunction(dataSourceFilter) && data) {
            data = dataSourceFilter(data);
        }
        if (isLazyTable()) {
            let fakeServer: any = createFakeServer(data);
            let newData: object = createServerSideDatasource(fakeServer);
            setTableData(gridTableApi)(newData);
        } else {
            setTableData(gridTableApi)(data);
        }
        setLoading(false);
    }, [props.dataSource, props.tableApi, props.isAddVirtual, props.dataSourceFilter, props.isLazyData, initTableParams]);

    const loadTreeData: Function = useCallback(async (gridTableApi: any, searchParams: any = {}, isSearch: boolean = false, searchUrl: string) => {
        setLoading(true);
        let {menuId, dataSource, tableApi = {}, dataSourceFilter, isAddVirtual = false}:
            {
                menuId: string,
                dataSource: any[],
                tableApi: any,
                dataSourceFilter: Function,
                isAddVirtual?: boolean
            } = props;
        let tableData: any[];
        if (dataSource) {
            tableData = dataSource
        } else {
            let {url, params = {}, method = "get", initParams = {}}: {
                url: string,
                method: string,
                params: any,
                initParams: any
            } = tableApi;
            params = {...initParams, ...params};
            setInitTableParams(params);
            let {data = [], records}: {
                data: any,
                records: number
            } = searchUrl || url ? (await AxiosSer(searchUrl || url, method, {
                ...params, ...searchParams,
                [axiosSerMenuKey]: menuId
            })) : {};
            setTotal(records);
            if (isAddVirtual) {
                data = treeMap(data, (children, item) => {
                    return {
                        ...item,
                        tableVirtualId: generateRandomId(),
                        children
                    }
                })
            }
            if (isFunction(dataSourceFilter) && data) {
                data = dataSourceFilter(data);
            }
            tableData = isArray(data) ? data : [data];
        }
        let fakeServer: any = createFakeServer(tableData);
        let newData: object = createServerSideDatasource(fakeServer);
        setTableData(gridTableApi)(newData);
        setLoading(false);
        // isSearch && setTimeout(() => {
        //     gridTableApi.expandAll();
        // }, 500)
    }, [props.dataSource, props.tableApi, props.menuId, props.isAddVirtual, props.dataSourceFilter, props.isLazyData, initTableParams, props.isTreeTable]);

    //获取分页表格数据
    const loadListData: Function = useCallback(async (tableApi: any = {}, paginationParams: any) => {
        let {url, method = "get", params = {}, initParams = {}}: {
            url: string,
            method?: string,
            params: any,
            initParams: any
        } = tableApi;
        params = {...initParams, ...params, ...initTableParams, ...paginationParams};
        let {data = []}: {
            data: any[]
        } = (await AxiosSer(url, method || "get", {
            ...params,
            [axiosSerMenuKey]: props.menuId
        }));
        if (props.isAddVirtual) {
            data = treeMap(data, (children, item) => {
                return {
                    ...item,
                    tableVirtualId: generateRandomId(),
                    children
                }
            })
        }
        if (isFunction(props.dataSourceFilter) && data) {
            data = props.dataSourceFilter(data);
        }
        return data;
    }, [props.tableApi, props.menuId, initTableParams, props.isAddVirtual, props.dataSourceFilter]);

    // 根据父节点获取子节点数据
    const loadTreeChildData: Function = useCallback(async (tableApi: any = props.tableApi, parentNode: any) => {
        const {url, method = "get", params = {}, urlRule, paramsRule, initParams = {}}: {
            url: string,
            method?: string,
            params: any,
            urlRule: string,
            paramsRule: any,
            initParams: any
        } = tableApi || {};
        let paramsRules: any = {};
        if (paramsRule && parentNode) {
            paramsRules = {
                ...getObjByRule(parentNode, paramsRule)
            }
        }
        let newParams: object = {...initParams, ...params, ...initTableParams, ...paramsRules};
        let {data = []}: {
            data: any[]
        } = await AxiosSer(urlRule || url, method || "get", {
            ...newParams,
            [axiosSerMenuKey]: props.menuId
        });
        if (props.isAddVirtual) {
            data = treeMap(data, (children, item) => {
                return {
                    ...item,
                    tableVirtualId: generateRandomId(),
                    children
                }
            })
        }
        // 判断是否存在数据过滤方法如果存在则进行数据过滤
        if (props.dataSourceFilter && isFunction(props.dataSourceFilter) && data) {
            data = props.dataSourceFilter(data, tableApi, parentNode);
        }
        return data;
    }, [props.tableApi, props.menuId, initTableParams, props.isAddVirtual, props.dataSourceFilter])

    // 获取表格数据
    const loadTable: Function = useCallback(async (gridTableApi: any, searchParams: any = {}, isSearch: boolean = false, searchUrl: string) => {
        searchParamsRef.current = searchParams || {};
        if (isTreeTable()) {
            loadTreeData(gridTableApi, searchParams, isSearch, searchUrl);
        } else {
            loadData(gridTableApi, searchParams, searchUrl);
        }
    }, [props.tableApi, props.menuId, props.dataSource, props.dataSourceFilter, props.isLazyData, initTableParams, firstColumn]);

    // 初始化表格
    const initCTable: Function = useCallback((gridTableApi: any) => {
        if (props.isInitSearch !== false) {
            loadTable(gridTableApi, {});
        } else {
            let newData: any = [];
            if (isLazyTable() || isTreeTable()) {
                let fakeServer: any = createFakeServer(newData);
                newData = createServerSideDatasource(fakeServer);
            }
            setTableData(gridTableApi)(newData);
        }
    }, [initTableParams, firstColumn, props.dataSource, props.tableApi, props.isInitSearch, props.isTreeTable, props.isLazyData]);

    //搜索表格数据
    const searchTable: Function = useCallback(async (searchParams: any = {}, isSearch: boolean = false, searchUrl: string) => {
        setIsSearchTable(isSearch);
        if (props.searchFn) {
            props.searchFn(searchParams)
        } else {
            await loadTable(gridTable.current, {...initTableParamsRef.current, ...searchParams}, isSearch, searchUrl);
        }
    }, [props.tableApi, props.menuId, props.dataSourceFilter, props.isLazyData, initTableParams, firstColumn]);

    // 添加表格数据方法
    const addTableData: Function = useCallback(async (data: any[], isAddLast: boolean = false, isAddType: boolean = true) => {
        if (!data) {
            return;
        }
        if (!isArray(data)) {
            data = [data];
        }
        const {parentKey = "parentId"}: {
            parentKey: string
        } = props;
        if (isTreeTable()) {
            data = await formatTreeTableData(data, isAddType);
            data.forEach(async (item: any) => {
                let newData: any = [item];
                let parentPath: any = item[parentKey] ? getParentPathById(gridTable.current, item[parentKey], isAddLast) : {
                    route: [],
                    index: 0
                };
                let sta = item[parentKey] ? updateUnChildData(gridTable.current, item[parentKey], newData) : updateInitData(newData);
                if (!sta) {
                    return
                }
                await applyTableData(gridTable.current)({
                    add: newData,
                    route: parentPath.route,
                    addIndex: isAddLast ? null : parentPath.index
                });
                item[parentKey] && gridTable.current.getRowNode(item[parentKey]).setExpanded(true);
                if (item.children) {
                    setTimeout(() => {
                        expandAllChildren(item)
                    }, 100)
                }
            })
        } else {
            updateInitData(data);
            applyTableData(gridTable.current)({
                add: data,
                addIndex: 0
            })
        }

    }, [props.tableApi, props.menuId, props.isTreeTable, props.rowKey, props.dataSourceFilter, firstColumn, props.parentKey]);

    // 修改表格数据方法
    const updateTableData: Function = useCallback((data: any) => {
        if (!data) {
            return;
        }
        if (isArray(data)) {
            treeFind(data, (item: any) => {
                let node = gridTable.current?.getRowNode(item[getKey()]);
                node && node.updateData({
                    [editStatusKey]: "update",
                    optBtn: "" + Math.random(),
                    ...item
                });
            })
        } else {
            let node = gridTable.current?.getRowNode(data[getKey()]);
            node.updateData({
                [editStatusKey]: "update",
                optBtn: "" + Math.random(),
                ...data
            });
        }
    }, [props.rowKey]);

    // 删除表格数据
    const deleteTableData: Function = useCallback((nodeIds: string[]) => {
        const {treeKey = "children"}: {
            treeKey: string
        } = props.tableApi || {};
        if (nodeIds && nodeIds.length) {
            nodeIds.forEach((nodeId: string) => {
                let node: any = gridTable.current?.getRowNode(nodeId);
                if (!node) {
                    return false;
                }
                let route: string[] = []
                if (isTreeTable()) {
                    route = getParentPathById(gridTable.current, nodeId).route;
                    route.pop();
                }
                // 从所有数据中移除
                allDataRef.current = treeFilterMap(allDataRef.current, (i: any) => i[getKey()] !== nodeId);
                // 从表格数据中移除
                applyTableData(gridTable.current)({route, remove: [node.data]});
                // 如果当前父只有一个子时，去掉父展开收起图标
                if (isTreeTable() && node.parent && node.parent.data.children && node.parent.data.children.length <= 1) {
                    node.parent.data[treeGroupKey] = false;
                    node.parent.data[treeKey] = [];
                    node.parent.updateData(node.parent.data);
                    node.parent.updateHasChildren();
                }
            })
        }
    }, [props.rowKey, props.isTreeTable]);


    // 监听表头数据变化
    useEffect(() => {
        loadView();
    }, [props.view, props.ds]);

    useEffect(() => {
        if (gridTable.current) {
            initCTable(gridTable.current);
        }
    }, [props.dataSource, JSON.stringify(props.tableApi), props.key]);

    useEffect(() => {
        if (props.autoExpand && gridTable.current) {
            gridTable.current.refreshServerSide({route: [], purge: true});
        }
    }, [props.autoExpand])

    useImperativeHandle(props.init, () => {
        return {
            searchTable,
            addTableData,
            updateTableData,
            deleteTableData,
            getTableSelectedRows,
            getTableAllRows,
            expandAllChildren,
            getExpandIdsObj: expandIdsObjRef.current,
            gridTable: () => {
                return gridTable.current;
            }
        };
    });

    const renderTotal = useMemo(() => {
        let isTotal = isNumber(total);
        return (
            <div className="sf_core_table_header_total">
                {isTotal ? <>
                    <span className="sf_core_table_header_total_label">{t("all")}</span>
                    <span className="sf_core_table_header_total_split">|</span>
                    <span className="sf_core_table_header_total_text">{total}</span>
                    <span className="sf_core_table_header_total_label">{t("dataNum")}</span>
                    <span className="sf_core_table_header_total_split">|</span>
                </> : null}
                <span className="sf_core_table_header_total_label">{t("selectData")}</span>
                <span className="sf_core_table_header_total_text">{selectCount}</span>
            </div>
        )
    }, [total, selectCount]);

    const renderSearch = useMemo(() => {
        return (
            <div className="sf_core_table_header_search">
                {/* {isTreeTable() ? <>
                    <Select
                        placeholder={t("expansionLevel")}
                        size={"small"}
                    />
                </> : null} */}
                <Input.Search
                    size={"small"}
                    placeholder={t("keyword")}
                    onSearch={(value: string) => {
                        let searchParams = {[(isString(props.isShowHeader) ? formatLangStr(props.isShowHeader) : "keyword")]: value}
                        if (props.otherSearchFn) {
                            props.otherSearchFn(searchParams)
                        } else {
                            searchTable(searchParams, value ? true : false)
                        }
                    }}
                />
            </div>
        )
    }, [props]);

    const onRowGroupOpened = useCallback((e: any) => {
        if (e.expanded) {
            expandIdsObjRef.current[e.node.id] = e.node.data.id || true;
            if (e.node.id != e.node.data.id) {
                expandIdsObjRef.current[e.node.data.id] = e.node.id
            }
        } else {
            delete expandIdsObjRef.current[e.node.id];
            delete expandIdsObjRef.current[e.node.data.id];
        }
    }, [])

    const renderHeader = useMemo(() => {
        return (
            <div className="sf_core_table_header">
                {renderTotal}
                {renderSearch}
            </div>
        )
    }, [total, selectCount, props])

    const renderTable = useMemo(() => {
        let {
            headerHeight = 30,
            rowHeight = 30,
            rowSelection = 'multiple',
            isPagination = false,
            isParentLinkChild = false,
            isSideBar = false,
            otherRenderFn,
            otherTableParams
        }: {
            headerHeight?: number | undefined,
            rowHeight?: number | undefined,
            rowSelection: "single" | "multiple" | "clickMultiple",
            isPagination?: boolean,
            isParentLinkChild?: boolean | undefined,
            isSideBar?: boolean,
            otherRenderFn?: any,
            otherTableParams?: any
        } = props;
        if (!column.length && !firstColumn) {
            return null;
        }

        let components = getTableComAll(otherRenderFn);

        let AgGridParams: any = {
            ...otherTableParams,
            onGridReady: onGridReady,
            columnDefs: column,
            defaultColDef: {
                resizable: true,
                menuTabs: []
            },
            components: components,
            headerHeight: headerHeight,
            rowHeight: rowHeight,
            cacheBlockSize: pageSize,
            rowSelection: rowSelection === "single" ? "single" : "multiple",
            rowMultiSelectWithClick: rowSelection === "clickMultiple", //多选得时候，点击行可以多选
            onSortChanged: onSortChanged,
            isRowSelectable: isRowSelectable,
            onFirstDataRendered: isDefaultSelected,
            getRowId: getRowId,
            getRowStyle: getRowStyle,
            onRowGroupOpened: onRowGroupOpened,
            getContextMenuItems: () => {
            },
            onSelectionChanged: onSelectionChanged,
            onCellDoubleClicked: onCellDoubleClicked,
            enableCellTextSelection: true, //允许选择文字
            suppressClipboardPaste: true, //允许粘贴
        };
        if (isSideBar) {
            AgGridParams.sideBar = tableSideBar;
        }
        if (isPagination && !isLazyTable()) {
            AgGridParams.pagination = true;
            AgGridParams.paginationPageSize = pageSize;
        }

        if (isLazyTable() || isTreeTable()) {
            AgGridParams.rowModelType = "serverSide";
        }

        if (isTreeTable()) {
            AgGridParams = {
                ...AgGridParams,
                treeData: true,
                groupSelectsChildren: isParentLinkChild,
                getDataPath: getDataPath,
                isServerSideGroup: isServerSideGroup,
                isServerSideGroupOpenByDefault: isServerSideGroupOpenByDefault,
                getServerSideGroupKey: getServerSideGroupKey,
                autoGroupColumnDef: autoGroupColumnDef
            }
        }
        return (
            <AgGridReact {...AgGridParams} />
        )
    }, [loading, firstColumn, column, props.selectIds, props.isTreeTable, props.dataSource, props.height, props.isPagination, props.isSideBar, props.isLazyData, props.isParentLinkChild, props.autoExpand])

    // 主渲染表格方法
    const renderGrid = useMemo(() => {
        let {height, isShowHeader = 'keyword'} = props
        let boxHeight: any = height
        if (isShowHeader) {
            boxHeight = isString(height) ? ("calc(" + height + " - 37px)") : (height - 37);
        }
        return (
            <Spin wrapperClassName={"sf_core_table"}
                  spinning={loading}
                  style={{height: height}}>
                {!!isShowHeader ? renderHeader : null}
                <div
                    className="ag-theme-alpine"
                    style={{height: boxHeight}}
                >
                    {renderTable}
                </div>
            </Spin>
        )

    }, [loading, total, selectCount, firstColumn, column, props.selectIds, props.isTreeTable, props.dataSource, props.height, props.isPagination, props.isSideBar, props.isLazyData, props.isParentLinkChild, props.autoExpand]);
    return (renderGrid);
};

export default CTable;